package pool;

import com.hyacinth.utils.StringUtils;
import config.DBPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * HY数据源
 *
 * @author zhangfb
 * @version 1.0.0.1
 * @since JDK 1.8
 */
public class HYDataSource {

    private static final Logger LOGGER = LoggerFactory.getLogger(HYDataSource.class);

    /**
     * 数据源id
     **/
    protected long id;
    protected String name;

    protected ConnectionPool connectionPool;

    protected ReentrantLock lock;
    protected Condition notEmpty;
    protected Condition empty;

    private final static AtomicInteger dataSourceIdSeed = new AtomicInteger(0);
    /**
     * 是否初始化
     **/
    protected volatile boolean inited = false;

    public HYDataSource() {
        this(false);
    }

    public HYDataSource(boolean lockFair) {
        lock = new ReentrantLock(lockFair);
        notEmpty = lock.newCondition();
        empty = lock.newCondition();
    }

    /**
     * 初始化数据源
     */
    public void init() throws SQLException {
        if (inited) {
            return;
        }

        final ReentrantLock lock = this.lock;
        try {
            lock.lockInterruptibly();
        } catch (InterruptedException e) {
            throw new SQLException("interrupt", e);
        }

        boolean init = false;
        try {
            if (inited) {
                return;
            }
            this.id = createDataSourceId();
            // 初始化配置参数
            DBPoolConfig config = initConfig();
            connectionPool = new ConnectionPool(config);
            connectionPool.initPool();
        } catch (SQLException e) {
            LOGGER.error("{dataSource-" + this.getID() + "} init error", e);
            throw e;
        } catch (RuntimeException e){
            LOGGER.error("{dataSource-" + this.getID() + "} init error", e);
            throw e;
        } catch (Error e){
            LOGGER.error("{dataSource-" + this.getID() + "} init error", e);
            throw e;
        } finally {
            inited = true;
            lock.unlock();

            if (init) {
                String msg = "{dataSource-" + this.getID();

                if (StringUtils.isNotBlank(this.getName())) {
                    msg += ",";
                    msg += this.name;
                }

                msg += "} inited";

                LOGGER.info(msg);
            }
        }
    }


    public DBPoolConfig initConfig() {
        DBPoolConfig config = null;
        Properties prop = new Properties();
        try{
            prop.load(HYDataSource.class.getClassLoader().getResourceAsStream("db.properties"));
            config = new DBPoolConfig(prop);
        }catch(IOException e) {
            e.printStackTrace();
        }
        return config;
    }

    public boolean isInited() {
        return this.inited;
    }

    public static int createDataSourceId() {
        return dataSourceIdSeed.incrementAndGet();
    }

    public long getID() {
        return this.id;
    }

    public String getName() {
        if (name != null) {
            return name;
        }
        return "DataSource-" + System.identityHashCode(this);
    }
}
